#include <iostream>
#include <vector>
#include <unistd.h>
#include <cstdlib>
#include "task.hpp"

using namespace std;

enum Error
{
    ArgcError = 1,
    PipeError,
    ProcessNumError
};

//父进程与子进程进行通信的管道
class Channal
{

public:

    Channal(int wfd, int process_pid, string& pipe_name)
        :_wfd(wfd)
        ,_process_pid(process_pid)
        ,_pipe_name(pipe_name)
    {}

    ~Channal()
    {}

    int get_wfd() 
    {
        return _wfd;
    }

    int get_process_pid()
    {
        return _process_pid;
    }

    string get_pipe_name()
    {
        return _pipe_name;
    }

private:
    int _wfd;          //父进程要写入的管道
    int _process_pid;  //子进程pid
    string _pipe_name; //管道名字

};

//进程池，管理进程
class Processpool
{
public:

    Processpool(int process_num)
        :_process_num(process_num)
    {}    

    void Create_processpool(work_t work)
    {

        //创建进程并与主进程建立管道进行通信
        for(int i=0; i<_process_num; i++)
        {
            int pipefd[2];
            int pipe_return_value = pipe(pipefd);
            if (pipe_return_value < 0) 
                exit(PipeError);

            int fork_return_value = fork();
            if (fork_return_value == 0)
            {
                //子进程 读操作-r 关闭写操作
                close(pipefd[1]);
                dup2(pipefd[0], 0);
                //do
                work(pipefd[0]);
                exit(0);
            }

            //父进程 写操作-w 关闭读操作
            close(pipefd[0]);

            string pipe_name = "process_" + to_string(i);
            _processpool.push_back({pipefd[1], fork_return_value, pipe_name});

        }   
    }

    void send_task(int wfd, int task)
    {
        cout << "send task to : " << _processpool[wfd].get_wfd() << endl;
        write(_processpool[wfd].get_wfd(), &task, sizeof(task));
    }

    int rand_pipe()
    {
        static int pipe_code = 0;
        int return_code = pipe_code;

        pipe_code++;
        pipe_code %= _process_num;

        return return_code;
    }

    int rand_work()
    {
        return rand() % 3;
    }

    void close_wfd()
    {
        for(auto &e : _processpool)
        {
            cout << "管道：" << e.get_wfd() << "关闭完成" << endl;
            close(e.get_wfd());
        }
    }

    void recycle()
    {
        for(auto &e : _processpool)
        {          
            waitpid(e.get_process_pid(),nullptr,0);     
            cout << "进程：" << e.get_process_pid() <<"资源回收完成" << endl;      
        }
    }

    ~Processpool()
    {
        //首先关闭所有写端，使得读取返回值为0时子进程退出
        close_wfd();

        //父进程回收所有子进程资源
        recycle();
    }

private:
    int _process_num;
    vector<Channal> _processpool;
};

void run_task(Processpool* processpool)
{
    int cnt = 10;

    while(cnt--)
    {
        //随机选中管道
        int luck_pipe = processpool->rand_pipe();

        //随机选中工作
        int luck_work = processpool->rand_work();

        //父进程向管道发送任务
        processpool->send_task(luck_pipe, luck_work);

        sleep(1);
    }
}

int main(int argc, char* argv[])
{

    if(argc != 2)
    {
        cout << "Use: " << argv[0] << " Process_Num" << endl;
        return ArgcError; 
    }

    //要创建的进程数
    int process_num = atoi(argv[1]);
    if(process_num <= 0)
        return ProcessNumError;
    
    //创建进程池对象
    Processpool* processpool = new Processpool(process_num);
    processpool->Create_processpool(worker);  //创建好了，但是没有发送任务。

    srand((unsigned int)time(0));
    run_task(processpool);
   
    delete processpool;

    return 0;
}